﻿using UnityEngine;

namespace Mars.MeshUI
{
    public class MeshGridImg : MeshImg
    {
        private bool dynamic = false; //3000 5; 4000 4; 5000 3; 8000 2; >8000 1;
        private bool colorDirty = false;
        private bool fixInited = false;
        private bool scaleDirty = false;
        public int propEx = 5;

        public int fixedGridNum = -1;
        public int maxVerCount = 100;
        public bool noCreate = false;
        private int nowCount;
        private int addCount;
        private int dynamicPropEx = 5;
        private int screenWidth = 1334;
        private float canvasWidth = 1334f;

        int curBlackNum = 0;

        int blackNumWant = 0;

        //public bool debug = false;
        public float girdHeight = 5f; //分隔线默认高度
        public float girdExHeight = 10f;
        public float gridDefaultWidth = 2f; //分隔线默认宽度
        public float defaultMaxGridNum = 5; //分隔线默认最大个数，超过此阈值则按比例压缩格子宽度=gridDefaultWidth*curGridNum/MaxGridNum;
        public float valuePerGrid = 200f; //每格代表的值

        public bool delayInited = false;

        private float gWidth = 2f;
        private float curGridNum;
        private float hpScale = 1f;

        private float dynamicValuePerGrid = 200f;

        private float mscale = 1f;

        //scale变了或者残留格子数变了，都需要更新
        private float fixRemainGridFloat = -1;

        private float subGirdWidth = 1f;
        private float mainGirdWidth = 1f;
        readonly VertexData[] m_TempVerts = new VertexData[4];
        Color32 transparent = new Color32(0, 0, 0, 0);

        /// <summary>
        /// 分割线的生成策略
        /// </summary>
        /// <param name="value">最大值</param>
        /// <param name="thickSplitEach">每几个分割线一个粗分割线</param>
        /// <param name="valuePerSplit">每格数值</param>
        public delegate void GridSplitStrategy(float value, out int thickSplitEach, out float valuePerSplit);

        public GridSplitStrategy CurGridSplitStrategy
        {
            private get
            {
                if (m_curGridSplitStrategy == null)
                {
                    return GetDeleOf_DefaultGridSplitStrategy();
                }

                return m_curGridSplitStrategy;
            }
            set => m_curGridSplitStrategy = value;
        }

        private GridSplitStrategy m_curGridSplitStrategy = null;

        public override bool Init(MeshCanvas _canvas)
        {
            screenWidth = Screen.width;

            //if(UIRoot.instance != null && UIRoot.instance.RootCanvasTransform != null)
            //{
            //    canvasWidth = UIRoot.instance.RootCanvasTransform.rect.width;
            //}

            this.canvas = _canvas;

            if (!noCreate || vertices == null)
            {
                vertices = null;
                if (!delayInited)
                {
                    vertices = new VertexData[maxVerCount];
                }
            }
            else
            {
                var spriteUV = (activeSprite == null)
                    ? Vector4.zero
                    : UnityEngine.Sprites.DataUtility.GetOuterUV(activeSprite);
                for (int i = 0; i < vertices.Length; i++)
                {
                    vertices[i].position = new Vector3(rect.x, rect.y, 0);
                    vertices[i].uv.z = 0;
                    vertices[i].uv.w = 0;
                    switch (i % 4)
                    {
                        case 0:
                            vertices[i].uv.x = spriteUV.x;
                            vertices[i].uv.y = spriteUV.y;
                            break;
                        case 1:
                            vertices[i].uv.x = spriteUV.x;
                            vertices[i].uv.y = spriteUV.w;
                            break;
                        case 2:
                            vertices[i].uv.x = spriteUV.z;
                            vertices[i].uv.y = spriteUV.w;
                            break;
                        case 3:
                            vertices[i].uv.x = spriteUV.z;
                            vertices[i].uv.y = spriteUV.y;
                            break;
                    }
                }

                addCount = vertices.Length;

                SetCanvasFlagDirty(MeshCanvasDirtyFlag.kPosition | MeshCanvasDirtyFlag.kUv);
            }

            if (null != vertices && fixedGridNum > 0)
            {
                GenerateGridFixed();
            }

            return true;
        }

        public override bool Rebuild()
        {
            if (isVisible == false)
                return false;

            if (fixedGridNum > 0)
            {
                if (!fixInited || scaleDirty)
                {
                    GenerateGridFixed();
                    fixInited = true;
                }
                else if (colorDirty)
                {
                    BuildColor();
                }

                return true;
            }

            if (curGridNum > 0 && gridDirty)
            {
                GenerateGrid(curGridNum);
            }

            if (colorDirty)
            {
                BuildColor();
            }

            return true;
        }

        private bool gridDirty = false;

        private void GenerateGrid(float gridNum)
        {
            if (gridNum < 0.001f)
            {
                return;
            }

            gridDirty = false;
            int num = (int)gridNum;
            float deltaX = size.x / gridNum;

            //以下操作是为了短200血格子能够更容易被去除，长1000血格子要尽量保留
            if (num > 0 && num % (dynamic ? dynamicPropEx : propEx) == 0)
            {
                //长格子，1000血
                if (gridNum - num <= 0.01f)
                {
                    num = num - 1; //刚好是黑线结束时，去除末尾黑线
                }
            }
            else
            {
                //短格子，200血
                if (num * deltaX + gWidth + 1f >= size.x)
                {
                    num = num - 1; //若黑线压住血条末端，去除
                }
            }

            if (num <= 0)
            {
                return;
            }

            int vertCount = num * 4;

            if (vertCount > vertices.Length)
            {
                num = vertices.Length / 4;
                vertCount = vertices.Length;
            }

            for (int i = 0; i < num; i++)
            {
                float posX = rect.x + (i + 1) * deltaX;

                if (posX >= rect.x + size.x)
                {
                    break;
                }

                int quadCount = i * 4;
                float h = (i + 1) % (dynamic ? dynamicPropEx : propEx) == 0 ? girdExHeight : girdHeight;

                int posIntReal = Mathf.RoundToInt(hpScale * posX * screenWidth / canvasWidth); //换算为整数像素
                posX = posIntReal * canvasWidth / (screenWidth * hpScale); //canvasWidth / screenWidth为1像素对应的宽度

                if (dynamic)
                {
                    float tmp = (i + 1) % dynamicPropEx == 0 ? mainGirdWidth : subGirdWidth;
                    vertices[quadCount].position = new Vector3(posX, rect.w, 0);
                    vertices[quadCount + 1].position = new Vector3(posX, rect.w - h, 0);
                    float tmpX = (posX + tmp >= rect.x + size.x) ? (rect.x + size.x) : (posX + tmp);
                    vertices[quadCount + 2].position = new Vector3(tmpX, rect.w - h, 0);
                    vertices[quadCount + 3].position = new Vector3(tmpX, rect.w, 0);
                }
                else
                {
                    vertices[quadCount].position = new Vector3(posX, rect.w - h, 0);
                    vertices[quadCount + 1].position = new Vector3(posX, rect.w, 0);
                    vertices[quadCount + 2].position = new Vector3(posX + gWidth, rect.w, 0);
                    vertices[quadCount + 3].position = new Vector3(posX + gWidth, rect.w - h, 0);
                }

                if (colorDirty && i >= blackNumWant)
                {
                    vertices[quadCount].color = transparent;
                    vertices[quadCount + 1].color = transparent;
                    vertices[quadCount + 2].color = transparent;
                    vertices[quadCount + 3].color = transparent;
                }
                else
                {
                    vertices[quadCount].color = color;
                    vertices[quadCount + 1].color = color;
                    vertices[quadCount + 2].color = color;
                    vertices[quadCount + 3].color = color;
                }

                var spriteUV = (activeSprite == null)
                    ? Vector4.zero
                    : UnityEngine.Sprites.DataUtility.GetOuterUV(activeSprite);

                SetUv(spriteUV.x, spriteUV.y, quadCount);
                SetUv(spriteUV.x, spriteUV.w, quadCount + 1);
                SetUv(spriteUV.z, spriteUV.w, quadCount + 2);
                SetUv(spriteUV.z, spriteUV.y, quadCount + 3);
            }

            if (nowCount > vertCount)
            {
                for (int i = vertCount; i < nowCount; i++)
                {
                    vertices[i].position = Vector3.zero;
                }
            }

            nowCount = vertCount;

            curBlackNum = blackNumWant;
            colorDirty = false;

            SetCanvasFlagDirty(MeshCanvasDirtyFlag.kAll);
            canvas.SetVertexDataById(MeshCanvasIndex, VerticesData, IndicType);
            canvas.SetVertexLenghtDirtyById(MeshCanvasIndex, nowCount);
        }

        void SetUv(float x, float y, int index)
        {
            vertices[index].uv.x = x;
            vertices[index].uv.y = y;
        }

        public bool IsUnityEditor()
        {
#if UNITY_EDITOR
            return true;
#else
        return false;
#endif
        }

        private void SetAndAdaptGridWidth(float _gridWidth)
        {
            gWidth = _gridWidth;
            if (IsUnityEditor() && !Application.isPlaying)
            {
                // 编辑器下并且不运行限定在1和2之间
                gWidth = Mathf.Clamp(Mathf.RoundToInt(gWidth), 1, 2);
            }
            else
            {
                int pixelNum =
                    Mathf.Clamp(Mathf.RoundToInt(hpScale * gWidth * screenWidth / canvasWidth), 2, 999); //换算为整数像素
                gWidth = pixelNum * canvasWidth / (screenWidth * hpScale); //canvasWidth / screenWidth为1像素对应的宽度
            }
        }

        public void DrawGirdAndUpdateColor(float maxValue, float curValue, float customValuePerGrid = 0f)
        {
            DrawGrid(maxValue, customValuePerGrid);
            if (dynamic && dynamicValuePerGrid > float.Epsilon)
            {
                blackNumWant = (int)(curValue / dynamicValuePerGrid);
            }
            else if (valuePerGrid > float.Epsilon)
            {
                blackNumWant = (int)(curValue / valuePerGrid);
            }
            else
            {
                blackNumWant = 0;
            }

            colorDirty = true;
            //if (debug) Log.Error(blackNumWant + " " + colorDirty);
        }

        public void DrawGrid(float value, float customValuePerGrid = 0f)
        {
            if (valuePerGrid <= 0 && customValuePerGrid == 0f)
            {
                return;
            }

            if (vertices == null && delayInited)
            {
                vertices = new VertexData[maxVerCount];
            }

            if (dynamic)
            {
                if (customValuePerGrid == 0f)
                {
                    CurGridSplitStrategy(value, out dynamicPropEx, out dynamicValuePerGrid);
                }
                else
                {
                    dynamicPropEx = 5;
                    dynamicValuePerGrid = customValuePerGrid;
                }
            }

            if (dynamic && dynamicValuePerGrid > float.Epsilon)
            {
                curGridNum = value / dynamicValuePerGrid;
            }
            else if (valuePerGrid > float.Epsilon)
            {
                curGridNum = value / valuePerGrid;
            }
            else
            {
                curGridNum = 0;
            }

            if (dynamic)
            {
                AdaptDynamicWidth();
            }
            else
            {
                if (curGridNum <= defaultMaxGridNum)
                {
                    SetAndAdaptGridWidth(gridDefaultWidth);
                }
                else
                {
                    SetAndAdaptGridWidth(gridDefaultWidth * defaultMaxGridNum / curGridNum);
                }
            }

            gridDirty = true;
        }

        public void DrawFixedGrid(float gridNum)
        {
            curGridNum = gridNum;
            gridDirty = true;
            //if (debug) Log.Error(blackNumWant + " " + colorDirty);
        }

        public void SetMultiplyScale(float scale)
        {
            if (scale != mscale)
            {
                scaleDirty = true;
                colorDirty = true;
            }

            mscale = scale;
        }

        public void SetRemainGrid(float value) //curHp/maxHp
        {
            if (value != fixRemainGridFloat)
            {
                fixRemainGridFloat = value;
                int tmp = (int)(fixRemainGridFloat * (fixedGridNum + 1f));
                if (tmp != blackNumWant)
                {
                    blackNumWant = tmp;
                    colorDirty = true;
                }
            }
        }

        public void GenerateGridFixed()
        {
            int num = (int)fixedGridNum;
            float deltaX = size.x / (fixedGridNum + 1);

            int vertCount = num * 4;

            if (vertCount > vertices.Length)
            {
                num = vertices.Length / 4;
                vertCount = vertices.Length;
            }

            var spriteUV = (activeSprite == null)
                ? Vector4.zero
                : UnityEngine.Sprites.DataUtility.GetOuterUV(activeSprite);


            for (int i = 0; i < num; i++)
            {
                float posX = rect.x + (i + 1) * deltaX * mscale;

                if (posX >= rect.x + size.x)
                {
                    break;
                }

                int quadCount = i * 4;
                float h = (i + 1) % (dynamic ? dynamicPropEx : propEx) == 0 ? girdExHeight : girdHeight;

                int posIntReal = Mathf.RoundToInt(hpScale * posX * screenWidth / canvasWidth); //换算为整数像素
                posX = posIntReal * canvasWidth / (screenWidth * hpScale); //canvasWidth / screenWidth为1像素对应的宽度

                vertices[quadCount].position = new Vector3(posX, rect.w, 0);
                vertices[quadCount + 1].position = new Vector3(posX, rect.w - h, 0);
                vertices[quadCount + 2].position = new Vector3(posX + gWidth, rect.w - h, 0);
                vertices[quadCount + 3].position = new Vector3(posX + gWidth, rect.w, 0);

                if (colorDirty && i >= blackNumWant)
                {
                    vertices[quadCount].color = transparent;
                    vertices[quadCount + 1].color = transparent;
                    vertices[quadCount + 2].color = transparent;
                    vertices[quadCount + 3].color = transparent;
                }
                else
                {
                    vertices[quadCount].color = color;
                    vertices[quadCount + 1].color = color;
                    vertices[quadCount + 2].color = color;
                    vertices[quadCount + 3].color = color;
                }


                SetUv(spriteUV.x, spriteUV.y, quadCount);
                SetUv(spriteUV.x, spriteUV.w, quadCount + 1);
                SetUv(spriteUV.z, spriteUV.w, quadCount + 2);
                SetUv(spriteUV.z, spriteUV.y, quadCount + 3);
            }

            if (nowCount > vertCount)
            {
                for (int i = vertCount; i < nowCount; i++)
                {
                    vertices[i].position = Vector3.zero;
                }
            }

            nowCount = vertCount;

            SetCanvasFlagDirty(MeshCanvasDirtyFlag.kAll);

            canvas.SetVertexLenghtDirtyById(MeshCanvasIndex, nowCount);
            canvas.SetVisibleDirtyById(MeshCanvasIndex, isVisible);

            curBlackNum = blackNumWant;
            colorDirty = false;
            scaleDirty = false;
        }

        public override void SetVisable(bool enable)
        {
            if (canvas == null)
                return;

            isVisible = enable;
            canvas.SetVisibleDirtyById(MeshCanvasIndex, enable);
            canvas.SetVertexLenghtDirtyById(MeshCanvasIndex, nowCount);
        }

        public override void OnPopulateMesh(VertexHelperEx toFill)
        {
        }

        public void SetHeadbarScale(float headbarLocalScale, float value)
        {
            hpScale = headbarLocalScale;
            DrawGrid(value);
        }

        public void SetHeadbarScaleDynamic(float headbarLocalScale, float value, float curHp)
        {
            if (dynamic)
            {
                hpScale = headbarLocalScale;
                DrawGirdAndUpdateColor(value, curHp);
            }
            else
            {
                SetHeadbarScale(headbarLocalScale, value);
            }
        }

        public void EnableDynamicGrid()
        {
            dynamic = true;
        }

        public void DisableDynamicGrid()
        {
            dynamic = false;
        }

        private void AdaptDynamicWidth()
        {
            int pixelNum = Mathf.Clamp(Mathf.RoundToInt(hpScale * 1f * screenWidth / canvasWidth), 2, 999); //换算为整数像素
            subGirdWidth = pixelNum * canvasWidth / (screenWidth * hpScale); //canvasWidth / screenWidth为1像素对应的宽度

            pixelNum = Mathf.Clamp(Mathf.RoundToInt(hpScale * gridDefaultWidth * screenWidth / canvasWidth), 3,
                999); //换算为整数像素
            mainGirdWidth = pixelNum * canvasWidth / (screenWidth * hpScale); //canvasWidth / screenWidth为1像素对应的宽度
        }

        public void UpdateAlpha(float curHP)
        {
            if (dynamicValuePerGrid > float.Epsilon)
            {
                blackNumWant = Mathf.Min((int)(curHP / dynamicValuePerGrid), nowCount / 4);
                colorDirty = (blackNumWant != curBlackNum);
                //if (debug) Log.Error(blackNumWant + " " + colorDirty);
            }
        }

        public void BuildColor()
        {
            if (blackNumWant != curBlackNum)
            {
                if (blackNumWant < curBlackNum)
                {
                    for (int i = 0, tmp = curBlackNum - blackNumWant; i < tmp; i++)
                    {
                        int index = (blackNumWant + i) * 4;
                        if (index + 3 < vertices.Length)
                        {
                            vertices[index].color = transparent;
                            vertices[index + 1].color = transparent;
                            vertices[index + 2].color = transparent;
                            vertices[index + 3].color = transparent;
                        }
                    }
                }
                else
                {
                    for (int i = 0, tmp = blackNumWant - curBlackNum; i < tmp; i++)
                    {
                        int index = (curBlackNum + i) * 4;
                        if (index + 3 < vertices.Length)
                        {
                            vertices[index].color = color;
                            vertices[index + 1].color = color;
                            vertices[index + 2].color = color;
                            vertices[index + 3].color = color;
                        }
                    }
                }

                SetCanvasFlagDirty(MeshCanvasDirtyFlag.kColor);
                curBlackNum = blackNumWant;
            }

            colorDirty = false;
        }

        private GridSplitStrategy deleCacheOf_DefaultGridSplitStrategy = null;

        private GridSplitStrategy GetDeleOf_DefaultGridSplitStrategy()
        {
            return deleCacheOf_DefaultGridSplitStrategy == null
                ? deleCacheOf_DefaultGridSplitStrategy = DefaultGridSplitStrategy
                : deleCacheOf_DefaultGridSplitStrategy;
        }

        private void DefaultGridSplitStrategy(float value, out int thickSplitEach, out float valuePerSplit)
        {
            if (value <= 3000)
            {
                thickSplitEach = 5;
                valuePerSplit = 200f;
            }
            else if (value <= 4000)
            {
                thickSplitEach = 4;
                valuePerSplit = 250f;
            }
            else if (value <= 5000)
            {
                thickSplitEach = 3;
                valuePerSplit = 333.3333f;
            }
            else if (value <= 8000)
            {
                thickSplitEach = 2;
                valuePerSplit = 500f;
            }
            else if (value <= 20000f)
            {
                thickSplitEach = 1;
                valuePerSplit = 1000f;
            }
            else
            {
                thickSplitEach = 1;
                valuePerSplit = 10000f;
                int num = (int)(value * 0.0005f);
                while (num > 10)
                {
                    num /= 10;
                    valuePerSplit *= 10;
                }
            }
        }
    }
}